package com.notecalendar.quartz;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.util.List;
import java.util.Properties;

import org.apache.log4j.Logger;
import org.quartz.CronScheduleBuilder;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


import com.evernote.edam.type.Note;
import com.evernote.edam.type.Notebook;
import com.notecalendar.EvernoteBean;
import com.notecalendar.beans.Evernote;
import com.notecalendar.beans.EvernoteEmail;
import com.notecalendar.bo.Evernote_FileBo;
import com.notecalendar.bo.Evernote_LoginBo;
import com.notecalendar.bo.NotesBo;
import com.notecalendar.bo.impl.Evernote_FileBoImpl;
import com.notecalendar.bo.impl.Evernote_LoginBoImpl;
import com.notecalendar.bo.impl.NotesBoImpl;
import com.notecalendar.exception.EvernoteBeanException;
import com.notecalendar.model.Alarm_Types;
import com.notecalendar.model.Evernote_File;
import com.notecalendar.model.Evernote_Login;
import com.notecalendar.model.Notes;
import com.notecalendar.quartz.exception.QuartzException;
import com.notecalendar.ws.beans.EvernoteUser;

/**
 * Class for working with Quartz library
 * @author bcamcereijo
 *
 */
public class QuartzUtil implements Job{
	
	//System log
	private Logger logger = Logger.getLogger(QuartzUtil.class);

	//properties for quartz
	private Properties quartzProperties = null;
	
	
	//injected via spring
	private Evernote_FileBo evernote_FileBo;
	private Evernote_LoginBo evernote_loginBo;
	private EvernoteBean evernoteBean;
	private NotesBo noteBo;
	
	public void setEvernote_FileBo(Evernote_FileBo evernote_FileBo) {
		this.evernote_FileBo = evernote_FileBo;
	}
	public void setEvernoteBean(EvernoteBean evernoteBean) {

		this.evernoteBean = evernoteBean;
	}
	public void setNoteBo(NotesBo noteBo) {
		this.noteBo = noteBo;
	}
	public void setEvernote_loginBo(Evernote_LoginBo evernote_loginBo) {
		this.evernote_loginBo = evernote_loginBo;
	}
	
	/**
	 * Default constructor
	 */
	public QuartzUtil() {
	}
	
	
	/**
	 * Create a new task y quartz
	 * @param evernoteBean
	 * @param quartzCalendar
	 * @return
	 */
	public boolean programNote(Evernote evernote, QuartzCalendar quartzCalendar){
		//save note on data file
		try{
			//write object into bytearray
			ByteArrayOutputStream bout = new ByteArrayOutputStream();
			ObjectOutputStream outf = new ObjectOutputStream(bout);
			
			outf.writeObject(evernote);
			
			outf.close();
			bout.close();
		    
		    Evernote_File evernote_file = new Evernote_File();
		    	evernote_file.setFile(bout.toByteArray());
		    	evernote_file.setEvernote_id(evernote.getEvernote_id());

		    //insert content en db
		    evernote_file = evernote_FileBo.insertEvernote_File(evernote_file);
		    
		    //create quartz task
		    createQuartzTask(evernote_file.getId(), quartzCalendar);
		    
		    return true;
		}catch(Exception e){
			e.printStackTrace();
			return false;
		}

	}
	
	/**
	 * Insert a new task 
	 * @param evernote_file_id
	 * @param listaAlarmTypes
	 * @param quartzCalendar
	 */
	private void createQuartzTask(BigInteger evernote_file_id, QuartzCalendar quartzCalendar)  throws QuartzException{
		try {
			//load file properties for Quartz
			if(this.quartzProperties == null){
				this.quartzProperties = new Properties();
				this.quartzProperties.load(QuartzUtil.class
					.getResourceAsStream("properties/quartz.properties"));
			}

			SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory(
					this.quartzProperties);
			Scheduler sched = schedFact.getScheduler();
			sched.start();
			
			
			JobDetail jobDetail = JobBuilder.newJob(QuartzUtil.class).withIdentity(
					quartzProperties.getProperty("jobdetail.name") + evernote_file_id,
					quartzProperties.getProperty("jobdetail.group"))
			.build();
			
			//set parameters
			jobDetail.getJobDataMap().put("evernote_file_id", evernote_file_id);
			
			
			 Trigger trigger = TriggerBuilder.newTrigger() 
             .withIdentity(
            		 quartzProperties.getProperty("trigger.name")+evernote_file_id,
            		 quartzProperties.getProperty("trigger.group"))
             .withSchedule(
            		 CronScheduleBuilder.cronSchedule(quartzCalendar.getQuartzCronExpresion()))
             .build();
			
			/*
			 * Seconds Minutes Hours Day-of-Month Month Day-of-Week Year
			 */
			/*
			 * trigger.setCronExpression( "0 0 12 ? * SUN" );
			 */
			sched.scheduleJob(jobDetail, trigger);
			
		} catch (Exception e) {
			e.printStackTrace();
			throw new QuartzException(QuartzException.GENERAL_EXCEPTION);
		}
	}
	
	/**
	 * Execute task 
	 * @param cntxt
	 */
	public void execute(JobExecutionContext cntxt) throws JobExecutionException {
		try{
			//Manual DI
			ApplicationContext context = new ClassPathXmlApplicationContext(
					"classpath:applicationContext.xml");
			
			BeanFactory factory = context;
			evernoteBean  = (EvernoteBean) factory.getBean("evernoteBean");
			evernote_FileBo = (Evernote_FileBoImpl) factory.getBean("evernote_FileBo");
			noteBo = (NotesBoImpl) factory.getBean("noteBo");
			evernote_loginBo = (Evernote_LoginBoImpl) factory.getBean("evernote_loginBo");
		}catch(Exception e){
			System.out.println(e.getMessage());
			e.printStackTrace();
			return;
		}
		
		
		logger.info("Execute");
		//get parameters  evernote_file_id,listaAlarmTypes
		BigInteger evernote_file_id = (BigInteger)cntxt.getJobDetail().getJobDataMap().get("evernote_file_id");
		
		logger.info("evernote_file_id:"+evernote_file_id);
		
		logger.info("evernote_fileBo:"+evernote_FileBo);
		
		//read note from db for evernote_file_id
		Evernote_File evernote_file = evernote_FileBo.findEvernote_File(evernote_file_id);
		logger.info("evernote_file:"+evernote_file);
		
		//read de file content 
		ObjectInputStream inf;
		try {
			
			inf = new ObjectInputStream(new ByteArrayInputStream(evernote_file.getFile()));

			Evernote evernote = (Evernote)inf.readObject();
			logger.info("note:"+evernote);
			
			//Look for user by id
			Evernote_Login evernote_login = evernote_loginBo.findEvernote_LoginById(
					evernote_file.getEvernote_id());
			
			logger.info("evernote_login:"+evernote_login);
			
			//insert note on evernote system
			//boolean insert = evernoteBean.evernoteSystemInit(evernote_login);
			//System.out.println("insert:"+insert);
			//String authToken = evernoteBean.evernoteSystemInit(evernote_login);
			EvernoteUser user = evernoteBean.evernoteSystemInit(evernote_login);
			//System.out.println("authToken:"+authToken);
			logger.info("authToken:"+user);
			Note note = evernote.getNote();
			
			switch(evernote.getEvernoteAction()){
				case Evernote.EVERNOTE_CREATE_NOTE:
					note = evernoteBean.insertNote(note, user.getShardId());
					break;
				case Evernote.EVERNOTE_CREATE_NOTEBOOK:
					evernoteBean.createNotebook(evernote.getNotebook(), user.getShardId(),
							user.getAuthToken());
					break;
				case Evernote.EVERNOTE_DELETE_NOTE:break;
				case Evernote.EVERNOTE_SHARE_NOTE:break;
				case Evernote.EVERNOTE_SHARE_NOTEBOOK:break;
				case Evernote.EVERNOTE_UNSHARE_NOTE:break;
				case Evernote.EVERNOTE_UNSHARE_NOTEBOOK:break;
			}
			
			
			
			logger.info("note evernote:"+note);
			
			//insert notification on notes table for every elements in listaAlarmTypes
			for(Alarm_Types alarm_type : evernote.getListAlarmTypes()){
				logger.info("alarm_type.idb:"+alarm_type.getId());
				logger.info("alarm_type.idb:"+alarm_type.getName());
				
				EvernoteEmail evernoteEmail = evernote.getEvernoteEmail();
				
				if(alarm_type.getId() == Alarm_Types.ALARM_TYPE_EMAIL && evernoteEmail!=null){
					//Send a note by email
					
					logger.info("note:"+note.getGuid()+" mail0:"+evernoteEmail.getEmailList().get(0)+
							" subject:"+evernoteEmail.getSubject()+" message:"+evernoteEmail.getMessage());
					
					evernoteBean.sendNoteByEmail(note, evernoteEmail.getEmailList(), evernoteEmail.getSubject(), 
							evernoteEmail.getMessage(),user.getShardId(), user.getAuthToken());
					logger.info("Sended a note by email");
				}else{
					Notes notes = new Notes();
						notes.setId_alarm_type(alarm_type.getId());
						notes.setId_evernote(note.getGuid());
					noteBo.insertNote(notes);
					logger.info("insert db:"+notes);
				}
			}
			
			//shutdown the scheduler
			cntxt.getScheduler().shutdown();
			
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (EvernoteBeanException e) {
			e.printStackTrace();
		} catch (SchedulerException e) {
			e.printStackTrace();
		}catch(Exception e){
			e.printStackTrace();
		}
		
	}


}
